#include "nasal.h"
#include "cli/cli.h"
#include "util/util.h"
#include "nasal_parse.h"

#include <iostream>
#include <thread>
#include <cstdlib>
#include <ctime>

namespace nasal::cli {

cli_config parse(const std::vector<std::string>& args) {
    cli_config result;

    for (const auto& arg : args) {
        if (cli_options.count(arg)) {
            result.options.insert(cli_options.at(arg));
        } else if (!result.input_file_path.length()) {
            result.input_file_path = arg;
        } else {
            result.nasal_vm_args.push_back(arg);
        }
    }

    if (result.input_file_path.length() && result.options.empty()) {
        result.options.insert(option::cli_execute);
    }
    return result;
}

std::ostream& help(std::ostream& out) {
    out
    << "\n"
    << "     ,--#-,\n"
    << "<3  / \\____\\  <3\n"
    << "    |_|__A_|\n"
    << "\nnasal <option>\n"
    << "option:\n"
    << "   -h,   --help     | get help.\n"
    << "   -v,   --version  | get version.\n"
    << "   -r,   --repl     | use repl interpreter.\n"
    << "\nnasal [option] <file> [argv]\n"
    << "option:\n"
    << "   -a,   --ast      | view ast after link/optimize process.\n"
    << "         --raw-ast  | view ast without after-processing.\n"
    << "   -c,   --code     | view generated bytecode.\n"
    << "   -s,   --symbol   | show analysed symbol info.\n"
    << "   -e,   --exec     | execute directly.\n"
    << "   -t,   --time     | show execute time.\n"
    << "   -d,   --detail   | get detail info.\n"
    << "   -f,   --ref-file | get referenced files.\n"
    << "   -dbg, --debug    | debug mode.\n"
    << "         --prof     | show profiling result, "
    << "available under debug mode.\n"
    << "         --prof-all | show profiling result of all files, "
    << "available under debug mode.\n"
    << "         --limit    | use limited execution mode "
    << "(readonly api enabled).\n"
    << "file:\n"
    << "   <filename>       | execute file.\n"
    << "argv:\n"
    << "   <args>           | cmd arguments used in program.\n"
    << "\n";
    return out;
}

std::ostream& nasal_format_help(std::ostream& out) {
    out
    << "\n"
    << "     ,--#-,\n"
    << "<3  / \\____\\  <3\n"
    << "    |_|__A_|\n"
    << "\nnasal-format <option>\n"
    << "option:\n"
    << "   -h,   --help     | get help.\n"
    << "   -v,   --version  | get version.\n"
    << "\nnasal-format <file>\n"
    << "file:\n"
    << "   <filename>       | file to be formatted.\n"
    << "\n";
    return out;
}

std::ostream& logo(std::ostream& out) {
    out
    << "\n"
    << "       __                _\n"
    << "    /\\ \\ \\__ _ ___  __ _| |\n"
    << "   /  \\/ / _` / __|/ _` | |\n"
    << "  / /\\  / (_| \\__ \\ (_| | |\n"
    << "  \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
    << "\n"
    << "ver  : " << __nasver__
    << " " << nasal::util::get_platform()
    << " " << nasal::util::get_arch()
    << " (" << __DATE__ << " " << __TIME__ << ")\n"
    << "std  : c++ " << __cplusplus << "\n"
    << "core : " << std::thread::hardware_concurrency() << " core(s)\n"
    << "repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
    << "repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
    << "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
    << "\n"
    << "presented by fgprc members:\n"
    << " - http://fgprc.org\n"
    << " - http://fgprc.org.cn\n"
    << "\n"
    << "input <nasal -h> to get help.\n\n";
    return out;
}

std::ostream& version(std::ostream& out) {
    std::srand(static_cast<u32>(std::time(nullptr)));

    f64 num = 0;
    for (u32 i = 0; i<5; ++i) {
        num = (num+rand())*(1.0/(RAND_MAX+1.0));
    }
    // give you 5% to see this easter egg
    if (num<0.05) {
        nasal::parse::easter_egg();
    }

    out << "nasal version " << __nasver__;
    out << " " << nasal::util::get_platform();
    out << " " << nasal::util::get_arch();
    out << " (" << __DATE__ << " " << __TIME__ << ")\n";
    return out;
}

std::ostream& nasal_format_version(std::ostream& out) {
    out << "nasal-format version " << __nasver__ << "-beta";
    out << " " << nasal::util::get_platform();
    out << " " << nasal::util::get_arch();
    out << " (" << __DATE__ << " " << __TIME__ << ")\n";
    return out;
}

}